/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.cef.designtime.api.entity.increment.extractor;

import com.inspur.edp.cef.designtime.api.changecontrolrule.controlrule.basic.AbstractControlRule;
import com.inspur.edp.cef.designtime.api.changecontrolrule.controlrule.cm.CommonDataTypeControlRule;
import com.inspur.edp.cef.designtime.api.changecontrolrule.controlrule.cm.CommonFieldControlRule;
import com.inspur.edp.cef.designtime.api.changecontrolrule.controlruledef.basic.entity.ControlRuleValue;
import com.inspur.edp.cef.designtime.api.changecontrolrule.controlruledef.cm.CommonDataTypeControlRuleDef;
import com.inspur.edp.cef.designtime.api.changecontrolrule.controlruledef.cm.CommonFieldContrulRuleDef;
import com.inspur.edp.cef.designtime.api.element.increment.extract.CommonFieldIncrementExtractor;
import com.inspur.edp.cef.designtime.api.entity.GspCommonDataType;
import com.inspur.edp.cef.designtime.api.entity.GspCommonField;
import com.inspur.edp.cef.designtime.api.entity.increment.ModifyEntityIncrement;
import com.inspur.edp.cef.designtime.api.increment.IncrementType;
import com.inspur.edp.cef.designtime.api.increment.extractor.ExtractUtils;
import com.inspur.edp.cef.designtime.api.json.CefNames;
import java.util.ArrayList;
import java.util.Map;
import lombok.var;

public class ModifyEntityExtractor {

    protected boolean includeAll;

    public ModifyEntityExtractor(){

    }

    public ModifyEntityExtractor(boolean includeAll){

        this.includeAll = includeAll;
    }
    public ModifyEntityIncrement extract(
            GspCommonDataType oldDataType,
            GspCommonDataType newDataType,
            CommonDataTypeControlRule rule,
            CommonDataTypeControlRuleDef def) {

        ModifyEntityIncrement increment = createModifyEntityIncrement();
        increment.setId(oldDataType.getId());
        //ChangeProperties()
        extractSelfInfo(increment, oldDataType, newDataType, rule, def);
        //fields
        extractFieldsIncrement(increment, oldDataType, newDataType, rule, def);
        //Child
        extractExtendIncrement(increment, oldDataType, newDataType, rule, def);

        if(increment.getChangeProperties().size() < 1 && increment.getChildEntitis().size() < 1&& increment.getFields().size() < 1)
            return null;
        return increment;
    }

    //region BaseInfo
    private void extractSelfInfo(
            ModifyEntityIncrement increment,
            GspCommonDataType oldDataType,
            GspCommonDataType newDataType,
            CommonDataTypeControlRule rule,
            CommonDataTypeControlRuleDef def) {
        if(includeAll){
            extractSelfAllInfo(increment,oldDataType,newDataType);
            return;
        }

        ExtractUtils.extractValue(
                increment.getChangeProperties(),
                oldDataType.getName(),
                newDataType.getName(),
                CefNames.Name,
                rule.getNameControlRule(),
                def.getNameControlRule());

    }

    private void extractSelfAllInfo(
            ModifyEntityIncrement increment,
            GspCommonDataType oldDataType,
            GspCommonDataType newDataType){
        ExtractUtils.extractValue(increment.getChangeProperties(), oldDataType.getCode(), newDataType.getCode(), CefNames.Code, null,null);
        ExtractUtils.extractValue(increment.getChangeProperties(), oldDataType.getName(), newDataType.getName(), CefNames.Name, null,null);
        ExtractUtils.extractValue(increment.getChangeProperties(), oldDataType.getIsRef(), newDataType.getIsRef(), CefNames.IsRef, null,null);
        ExtractUtils.extractValue(increment.getChangeProperties(), oldDataType.getI18nResourceInfoPrefix(), newDataType.getI18nResourceInfoPrefix(), CefNames.I18nResourceInfoPrefix, null,null);
        ExtractUtils.extractValue(increment.getChangeProperties(), oldDataType.getBeLabel(), newDataType.getBeLabel(), CefNames.BeLabel, null,null);
//        SerializerUtils.writePropertyValue(jsonGenerator,CefNames.CustomizationInfo,oldDataType.getCustomizationInfo());
    }

    //endregion

    //region Fields
    private void extractFieldsIncrement(
            ModifyEntityIncrement increment,
            GspCommonDataType oldDataType,
            GspCommonDataType newDataType,
            CommonDataTypeControlRule rule,
            CommonDataTypeControlRuleDef def) {

        var newElements = newDataType.getContainElements();
        if (newElements == null || newElements.size() < 1)
            throw new RuntimeException("节点" + newDataType.getCode() + "中没有字段，请检查");

        Map<String, AbstractControlRule> elementRules = rule.getChildRules().get(CefNames.Element);
        var fieldExtractor = createFieldExtractor();
        CommonFieldContrulRuleDef fieldContrulRuleDef = (CommonFieldContrulRuleDef)def.getChildControlRules().get(CefNames.Element);
        ArrayList<String> updateEles = new ArrayList<>();
        for (var newElement : newElements) {
            var oldElement = oldDataType.findElement(newElement.getID());
            if (oldElement != null)
                updateEles.add(oldElement.getID());


            var fieldIncreament = fieldExtractor.extractorIncrement(
                    (GspCommonField) oldElement,
                    (GspCommonField) newElement,
                    oldElement == null ? null : (CommonFieldControlRule)elementRules.get(oldElement.getID()),
                    fieldContrulRuleDef);
            if(fieldIncreament == null)
                continue;
            if (fieldIncreament.getIncrementType() == IncrementType.Added && !isAllowAddFields(rule, def))
                throw new RuntimeException("当前节点" + oldDataType.getCode() + "不允许添加字段");

            increment.getFields().put(newElement.getID(), fieldIncreament);

        }


        for (var oldElement : oldDataType.getContainElements()) {
            if (updateEles.contains(oldElement.getID()))
                continue;
            var fieldIncrement = fieldExtractor.extractorIncrement(
                    (GspCommonField) oldElement,
                    null,
                    (CommonFieldControlRule)elementRules.get(oldElement.getID()),
                    fieldContrulRuleDef);
            increment.getFields().put(oldElement.getID(), fieldIncrement);
        }

    }

    protected CommonFieldIncrementExtractor createFieldExtractor(){
        return new CommonFieldIncrementExtractor(includeAll);
    }


    private boolean isAllowAddFields(CommonDataTypeControlRule rule, CommonDataTypeControlRuleDef def) {
        switch (rule.getAddFieldControlRule().getControlRuleValue()){
            case Allow:
                return true;
            case Forbiddon:
                return false;
            case Default:
                return def.getAddFieldControlRule().getDefaultRuleValue() == ControlRuleValue.Allow;
        }

        return false;
    }
    //endregion

//    //region ChildEntity

//    //endregion

    protected void extractExtendIncrement(
            ModifyEntityIncrement increment,
            GspCommonDataType oldDataType,
            GspCommonDataType newDataType,
            CommonDataTypeControlRule rule,
            CommonDataTypeControlRuleDef def){

    }
    protected ModifyEntityIncrement createModifyEntityIncrement(){
        return new ModifyEntityIncrement();
    }

}
